module modular_db.module_;

import modular_db.database;
import modular_db.module_qualification;
import modular_db.utils: _hasReadOnlyProperty;

enum isModule(M) =
    _hasReadOnlyProperty!(M, Database, q{database}) &&
    _hasReadOnlyProperty!(M, ModuleQualification, q{qualification});

template moduleFields() {
nothrow @safe:
    import modular_db.database: Database;
    import modular_db.module_qualification: ModuleQualification;

    private {
        Database _db;
        ModuleQualification _q;
    }

    static if (__traits(compiles, (ref Database db) pure @system @nogc => db)) // 2.081+
        @property inout(Database) database() inout pure @system @nogc { return _db; }
    else
        @property inout(Database) database() inout @system { return _db; }

    @property ModuleQualification qualification() const pure @nogc { return _q; }
}

alias ModuleLoaderModuleType(L) = typeof({
    Database db;
    L loader;
    const L constLoader;

    const char[ ] url = constLoader.url;
    long version_ = constLoader.version_;
    static assert(!is(typeof(constLoader.version_): int), "`version_` must have type `long`");

    alias M = typeof(loader.load(db, ModuleQualification.init));
    static assert(is(M == typeof(loader.setup(db, ModuleQualification.init))));
    static assert(is(M == typeof(loader.migrate(db, ModuleQualification.init, 1L))));
    static assert(isModule!M);
    return M.init;
}());

enum isModuleLoader(L) = is(ModuleLoaderModuleType!L);